use std::{fs, sync::mpsc::{self, Receiver, Sender}};

use eframe::egui;
use tokio::{runtime::Runtime, sync};

use super::Dialog;
use crate::utils::fd;

enum MessageInfo {
    TotalCount(usize),
    Delete,
}

// ----------------------------------------------------------------------------
pub struct DlgDelete {
    tx: Sender<MessageInfo>,
    rx: Receiver<MessageInfo>,
    delete_files: Vec<String>,
    doing: bool,
}

impl Default for DlgDelete {
    fn default() -> Self {
        let (tx, rx) = mpsc::channel::<MessageInfo>();

        Self {
            tx,
            rx,
            delete_files: Vec::new(),
            doing: false,
        }
    }
}
impl Dialog for DlgDelete {
    fn update(&mut self) {}

    fn ui(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) {
        if !self.delete_files.is_empty() {
            let mut open = true;
            egui::Window::new("Delete Confirm")
                .open(&mut open)
                .show(ctx, |ui| {
                    ui.label("是否确认删除");
                    if ui.button("确认").clicked() {
                        self.delete_files.iter().for_each(|val| {
                            let env_path = val.clone();
                            tokio::spawn(async move {
                                let timer = tokio::time::Instant::now();
                                if fs::metadata(&env_path).unwrap().is_file() {
                                    fs::remove_file(&env_path).expect(&format!("Error : remove file {}", env_path));
                                    return;
                                }

                                let fd_out = fd::run_fd(&env_path, "-a -tf");
                                println!("Tip : fd cost time = {:?}", timer.elapsed());
                                if fd_out.is_err() {
                                    return;
                                }

                                let timer = tokio::time::Instant::now();
                                let ret = fd_out.unwrap();
                                let dirs: Vec<&str> = ret.split('\n').collect();
                                let (tx, mut rx) = sync::mpsc::channel::<bool>(dirs.len());
                                for dir in dirs {
                                    if dir.is_empty() {
                                        continue;
                                    }

                                    let async_dir = String::from(dir);
                                    let tx_c = tx.clone();
                                    tokio::spawn(async move {
                                        std::fs::remove_file(&async_dir).expect(&format!("Error : remove file {}", async_dir));
                                        let _ = tx_c.send(true).await;
                                    });
                                }

                                drop(tx);
                                while let Some(_) = rx.recv().await {}
                                std::fs::remove_dir_all(&env_path).expect(&format!("Error : remove_dir_all {}", env_path));
                                println!("Tip : delete cost time = {:?}", timer.elapsed());
                            });
                        });
                        self.delete_files.clear();
                    }

                    if ui.button("取消").clicked() {
                        self.delete_files.clear();
                    }
                });
        }

        preview_files_being_dropped(ctx);

        // Collect dropped files:
        ctx.input(|i| {
            if !i.raw.dropped_files.is_empty() {
                i.raw.dropped_files.iter().for_each(|val| {
                    let path = val.path.clone();
                    self.delete_files
                        .push(path.unwrap().to_str().unwrap().to_string());
                });
            }
        });
    }
}

/// Preview hovering files:
fn preview_files_being_dropped(ctx: &egui::Context) {
    use egui::*;
    use std::fmt::Write as _;

    if !ctx.input(|i| i.raw.hovered_files.is_empty()) {
        let text = ctx.input(|i| {
            let mut text = "Dropping files:\n".to_owned();
            for file in &i.raw.hovered_files {
                if let Some(path) = &file.path {
                    write!(text, "\n{}", path.display()).ok();
                } else if !file.mime.is_empty() {
                    write!(text, "\n{}", file.mime).ok();
                } else {
                    text += "\n???";
                }
            }
            text
        });

        let painter =
            ctx.layer_painter(LayerId::new(Order::Foreground, Id::new("file_drop_target")));

        let screen_rect = ctx.screen_rect();
        painter.rect_filled(screen_rect, 0.0, Color32::from_black_alpha(192));
        painter.text(
            screen_rect.center(),
            Align2::CENTER_CENTER,
            text,
            TextStyle::Heading.resolve(&ctx.style()),
            Color32::WHITE,
        );
    }
}
